#pragma once
#include <memory>
#include "muduo/net/EventLoop.h"
#include "muduo/net/EventLoopThread.h"
#include "muduo/net/TimerId.h"
#include <fstream>
#include <mutex>
#include <iostream>
#include <unordered_map>

// 单例全局文件定时刷新日志器
namespace ns_log
{
    struct FileElem
    {
        using ptr = std::shared_ptr<FileElem>;
        std::ofstream _ofs;
        std::mutex _mutex;
    };
}

namespace ns_helper
{
    const double default_interval = 10.0;

    class FileTimerHelper
    {
    public:
        static FileTimerHelper &getInstance()
        {
            static FileTimerHelper timer;
            return timer;
        }

        void set_timer(const ns_log::FileElem::ptr &sp)
        {
            std::unique_lock<std::mutex> ulock(_mutex);
            auto iter = timer_map.find(sp);
            if (iter == timer_map.end())
            {
                timer_map[sp] = loop->runEvery(_interval, std::bind(&FileTimerHelper::timerCallback, this, sp));
            }
            else
            {
                std::cout << "该数据已经被设置过定时了\n";
            }
        }

        void cancel_timer(const ns_log::FileElem::ptr &sp)
        {
            std::unique_lock<std::mutex> ulock(_mutex);
            auto iter = timer_map.find(sp);
            if (iter != timer_map.end())
            {
                loop->cancel(iter->second);
                timer_map.erase(iter);
            }
        }

        void shutdown()
        {
            std::unique_lock<std::mutex> ulock(_mutex);
            if (_running)
            {
                _running = false;
                for (auto &kv : timer_map)
                {
                    loop->cancel(kv.second);
                }
                loop->quit();
            }
        }

    private:
        FileTimerHelper(double interval = default_interval)
            : _interval(interval), loop(loop_thread.startLoop()) {}
        ~FileTimerHelper()
        {
            if (_running)
            {
                shutdown();
            }
        }

        FileTimerHelper(const FileTimerHelper &) = delete;
        const FileTimerHelper &operator=(const FileTimerHelper &) = delete;

        void timerCallback(const ns_log::FileElem::ptr &sp)
        {
            std::unique_lock<std::mutex> ulock(sp->_mutex);
            if (sp->_ofs.is_open())
            {
                sp->_ofs.flush();
            }
        }

        double _interval;
        bool _running = true;
        // 存在多线程同时访问的需求，因此要加互斥锁
        std::mutex _mutex;

        std::unordered_map<ns_log::FileElem::ptr, muduo::net::TimerId> timer_map;
        muduo::net::EventLoopThread loop_thread;
        muduo::net::EventLoop *loop;
    };
}
